///////////////////////////////////////////////////////////////////////
// DiscFormatTrackAtOnce.cpp
//
// Wrapper for IDiscFormat2TrackAtOnce Interface
//
// Written by Nic Wilson
//

#include "StdAfx.h"
#include "DiscRecorder.h"
#include "DiscFormatTrackAtOnce.h"
#include "DiscFormatTrackAtOnceEvent.h"

CDiscFormatTrackAtOnce::CDiscFormatTrackAtOnce(void)
: m_discFormatTrackAtOnce(NULL)
, m_mediaTypesArray(NULL)
, m_hResult(0)
, m_hNotificationWnd(NULL)
, m_closeMedia(true)
{
}

CDiscFormatTrackAtOnce::~CDiscFormatTrackAtOnce(void)
{
	if (m_discFormatTrackAtOnce != NULL)
	{
		m_discFormatTrackAtOnce->Release();
		m_discFormatTrackAtOnce = NULL;  
	}
}

///////////////////////////////////////////////////////////////////////
//
// CDiscFormatTrackAtOnce::Initialize()
//
// Description:
//		Creates and initializes the IDiscFormat2Data interface
//
bool CDiscFormatTrackAtOnce::Initialize(CDiscRecorder* pDiscRecorder, const CString& clientName)
{
	ASSERT(pDiscRecorder != NULL);
	if (pDiscRecorder == NULL)
	{
		m_errorMessage = _T("Error - CDiscFormatData::Initialize - pDiscRecorder is NULL");
		return false;
	}

	//
	// Initialize the IDiscFormat2TrackAtOnce Interface
	m_hResult = CoCreateInstance(__uuidof(MsftDiscFormat2TrackAtOnce), NULL, CLSCTX_INPROC_SERVER,
			__uuidof(IDiscFormat2TrackAtOnce), (void**)&m_discFormatTrackAtOnce);
	if (!SUCCEEDED(m_hResult))
	{
		m_errorMessage.Format(_T("Unable to Initialize IDiscFormat2TrackAtOnce - Error:0x%08x"), m_hResult);
		return false;
	}

	//
	// Setup the Disc Format Information
	//
	VARIANT_BOOL isSupported = VARIANT_FALSE;
	m_hResult = m_discFormatTrackAtOnce->IsRecorderSupported(pDiscRecorder->GetInterface(), &isSupported);
	if (isSupported == VARIANT_FALSE)
	{
		m_errorMessage = _T("Recorder not supported");
		return false;
	}
	m_hResult = m_discFormatTrackAtOnce->put_Recorder(pDiscRecorder->GetInterface());
	if (!SUCCEEDED(m_hResult))
	{
		m_errorMessage.Format(_T("IDiscFormat2TrackAtOnce->put_Recorder Failed - Error:0x%08x"), m_hResult);
		return false;
	}

	m_hResult = m_discFormatTrackAtOnce->put_ClientName(clientName.AllocSysString());
	if (!SUCCEEDED(m_hResult))
	{
		m_errorMessage.Format(_T("IDiscFormat2TrackAtOnce->put_ClientName Failed - Error:0x%08x"), m_hResult);
		return false;
	}
	m_hResult = m_discFormatTrackAtOnce->get_SupportedMediaTypes(&m_mediaTypesArray);
	if (!SUCCEEDED(m_hResult))
	{
		m_errorMessage.Format(_T("IDiscFormat2TrackAtOnce->get_SupportedMediaTypes Failed - Error:0x%08x"), m_hResult);
		return false;
	}
	VARIANT_BOOL b;
	m_hResult = m_discFormatTrackAtOnce->IsCurrentMediaSupported(pDiscRecorder->GetInterface(), &b);
	if (!SUCCEEDED(m_hResult))
	{
		m_errorMessage.Format(_T("IDiscFormat2TrackAtOnce->IsCurrentMediaSupported Failed - Error:0x%08x"), m_hResult);
		return false;
	}
	// NOW PREPARE THE MEDIA, it will be ready to use
	m_hResult = m_discFormatTrackAtOnce->PrepareMedia();
	if (!SUCCEEDED(m_hResult))
	{
		m_errorMessage.Format(_T("IDiscFormat2TrackAtOnce->PrepareMedia Failed - Error:0x%08x"), m_hResult);
		return false;
	}
	VARIANT_BOOL vbool = pThis->m_BurnProof.GetCheck()?VARIANT_FALSE:VARIANT_TRUE; //VARIANT_FALSE means burn proof enabled
	m_hResult = m_discFormatTrackAtOnce->put_BufferUnderrunFreeDisabled(vbool);
	return true;
}

void CDiscFormatTrackAtOnce::FreeRecorder()
{
	if ((m_discFormatTrackAtOnce) != NULL) 
	{
		// Release the media now that we are done
		m_discFormatTrackAtOnce->ReleaseMedia();
		m_discFormatTrackAtOnce->put_Recorder(NULL);
	}
}

ULONG CDiscFormatTrackAtOnce::GetTotalSupportedMediaTypes()
{
	if (m_mediaTypesArray == NULL)
		return 0;

	return m_mediaTypesArray->rgsabound[0].cElements;
}

int CDiscFormatTrackAtOnce::GetSupportedMediaType(ULONG index)
{
	ASSERT(index < GetTotalSupportedMediaTypes());
	if (index < GetTotalSupportedMediaTypes())
	{
		if (m_mediaTypesArray)
		{
			return ((VARIANT*)(m_mediaTypesArray->pvData))[index].intVal;
		}
	}

	return 0;
}

bool CDiscFormatTrackAtOnce::BurnTrack(HWND hNotificationWnd, IStream* streamData)
{
	if (m_discFormatTrackAtOnce == NULL)
		return false;

	if (hNotificationWnd == NULL)
		return false;

	if (streamData == NULL)
		return false;

	m_streamData = streamData;
	m_hNotificationWnd = hNotificationWnd;

	// Create the event sink
	CDiscFormatTrackAtOnceEvent* eventSink = CDiscFormatTrackAtOnceEvent::CreateEventSink();
	if (eventSink == NULL)
	{
		m_errorMessage = _T("Unable to create event sink");
		return false;
	}

	if (!eventSink->ConnectDiscFormatTrackAtOnce(this))
	{
		m_errorMessage = _T("Unable to connect event sink with interface");
		return false;
	}

	eventSink->SetHwnd(m_hNotificationWnd);

	//m_discFormatTrackAtOnce->put_ForceMediaToBeClosed(m_closeMedia.GetCheck() ? VARIANT_TRUE : VARIANT_FALSE);

	IMAPI_MEDIA_PHYSICAL_TYPE mediaType;
	m_hResult = m_discFormatTrackAtOnce->get_CurrentPhysicalMediaType(&mediaType);
	if (SUCCEEDED(m_hResult))
	{
		VARIANT_BOOL rotation = VARIANT_TRUE;
		if (pThis->m_CheckUseCAV.GetCheck() == 0)
			rotation = VARIANT_FALSE;
		m_hResult = m_discFormatTrackAtOnce->SetWriteSpeed((LONG)pThis->GetSpeedSecsPerSecond(mediaType), rotation); //last parameter is VARIANT_TRUE for CAV or VARIANT_FALSE for other the drive supports,  default is VARIANT FALSE
	}
	IBurnVerification *burnVerifier = NULL;
	HRESULT hr = m_discFormatTrackAtOnce->QueryInterface(IID_PPV_ARGS(&burnVerifier));
	if (SUCCEEDED(hr))
	{
		IMAPI_BURN_VERIFICATION_LEVEL   VerificationLevel = (IMAPI_BURN_VERIFICATION_LEVEL)pThis->m_VerifyCombo.GetCurSel();
		hr = burnVerifier->put_BurnVerificationLevel(VerificationLevel);
	}
		m_hResult = m_discFormatTrackAtOnce->AddAudioTrack(m_streamData);
	delete eventSink;

	if (SUCCEEDED(m_hResult))
	{
		return true;
	}

	m_errorMessage.Format(_T("IDiscFormat2TrackAtOnce->Write Failed! Error:0x%08x"),
		m_hResult);

	return true;

}

IDiscFormat2TrackAtOnce* CDiscFormatTrackAtOnce::GetIDiscFormatTrackAtOncePtr()
{
	return m_discFormatTrackAtOnce;
}
